import { Context } from '../../../src/common';
import * as t from 'assert';
import { parseSource } from '../../../src/parser';

describe('Miscellaneous - Early errors', () => {
  for (const arg of [
    `{ a = 0 });`,
    `(...a)`,
    `(a, ...b)`,
    `(((...a))`,
    '(((a, ...b)))',
    '0++',
    '({a: 0} = 0);',
    `({a(b){}} = 0)`,
    '"use strict"; ({arguments = 1} = 2);',
    `[0] = 0;`,
    `0 = 0;`,
    `({a}) = 0;`,
    `([a]) = 0;`,
    `({a} += 0);`,
    `[a] *= 0;`,
    `0 /= 0;`,
    `[...{a: 0}] = 0;`,
    `[...[0]] = 0;`,
    `[...0] = 0;`,
    'a\\u{0}',
    'a\\u0000',
    '\\u{0}',
    '[...new a] = 0;',
    'for({a: 0} in 0);',
    'for([0] in 0);',
    'for(const let of 1);',
    'for([0] of 0);',
    'for(({a: 0}) in 0);',
    'for(([0]) in 0);',
    'for(({a: 0}) of 0);',
    '!function a(b = super[1]){}',
    'function *a() { (b = yield) => {} }',
    'for(([0]) of 0);',
    'for((0) of 0);',
    '\\u0000',
    '\\u{0}',
    'a\\u0000',
    '\\u{110000}',
    '\\u{FFFFFFF}',
    `/./\\u{69}`,
    //`async function a(){ (a = await (0)) => {}; }`,
    `async function a(b = await (0)) {}`,
    '(async function(b = await (0)) {})',
    '({ async a(b = await (0)) {} })',
    '(class { async constructor(){} })',
    "'use strict'; +implements;",
    "'use strict'; let:0;",
    "'use strict'; +yield;",
    "!{ get a() { 'use strict'; +let; } }",
    'class let {}',
    'class l\\u{65}t {}',
    '(class yield {})',
    '({ a(){ super(); } });',
    '"use strict"; ([yield] = a)',
    'class a extends b { constructor() { !{*constructor() { super(); }}; } }',
    '"use strict"; !function* arguments(){}',
    '!function(a){ super.b }',
    'class a extends b { static prototype(){} }',
    'function a() {"use strict"; ({ set b(eval) { } }); }',
    '!{ get a() { "use strict"; +let; } }',
    'function a(){ "use strict"; function a(yield){}}',
    '({ a(){ {{ if(0) (( super() )); }} } });',
    'class A extends B { constructor() { !{constructor() { super(); }}; } }',
    'class A extends B { constructor() { !{*constructor() { super(); }}; } }',
    'class A extends B { constructor() { !{get constructor() { super(); }}; } }',
    'class A extends B { constructor() { !{set constructor(a) { super(); }}; } }',
    "'use strict'; delete ((a));",
    'if(0) ; else label: function f(){}',
    'if(0) label: function f(){} else ;',
    'if(0) labelA: labelB: function f(){}',
    'for(let let in 0);',
    'for(const let in 0);',
    'for(let let of 0);',
    'for(const let of 0);',
    'while(0) !function(){ break; };',
    'if(0) break;',
    '{ break; }',
    'switch(0) { default: function f(){ break; } }',
    "'use strict'; function eval(){}",
    "'use strict'; function arguments(){}",
    "'use strict'; !function eval(){}",
    "'use strict'; !function arguments(){}",
    'function f(a = super.b){}',
    '!function f(a = super[0]){}',
    '!function(a = super.b){}',
    'function f(a){ super.b }',
    '!{ a() { !function(){ super.b(); } } };',
    'for(const a = 1, let = 2;;);',
    'var a = new.target;',
    'class A extends B { a() { function f(){ super.b(); } } }',
    'class A extends B { a() { !function(){ super.b(); } } }',
    'function f(a = super()){}',
    'class A extends B { constructor() { function f(a = super()){} } }',
    'class A extends B { constructor() { !function(a = super()){} } }',
    'function f(a){ super() }',
    '!function(a){ super() }',
    'function* g(){ ({[yield]: a}) => 0; }',
    'function* g(){ (a = x + f(yield)) => 0; }',
    'function* g(){ (a = yield* b) => 0; }',
    'function* g(){ (a = yield b) => 0; }',
    'function* g(){ (a = yield) => 0; }',
    'function* g(){ ({ *m(a = yield){} }); }',
    'function* g(){ ({ *m(a = yield b){} }); }',
    'function* g(){ ({ *m(a = yield* b){} }); }',
    'function* g(){ ({ *m({[yield]: a}){} }); }',
    'function* f(a){ super() }',
    'function* g(){ function* f(a = yield){} }',
    'function* g(){ function* f(a = yield b){} }',
    'function* g(){ function* f(a = yield* b){} }',
    'function* g(){ function* f(a = x + f(yield)){} }',
    'function* g(){ function* f({a = yield}){} }',
    'function* g(){ function* f([a = yield]){} }',
    'function* g(){ !function*(a = yield* b){} }',
    'function* g(){ !function*(a = x + f(yield)){} }',
    'function* g(){ !function*([a = yield]){} }',
    '!function* (a = super.b){}',
    'function* a(){ !function*([b = yield]){} }',
    'class a { b(eval){} };',
    '!{ a() { !function* (a = super.b()){} } };',
    'class A extends B { a() { function* f(a = super.b()){} } }',
    'class A extends B { a() { !function* (a = super.b()){} } }',
    '!{ a() { function* f(){ super.b(); } } };',
    'class A { constructor() { {{ (( super() )); }} } }',
    'class A { constructor() { super(); } }',
    'class A { *constructor(){} }',
    'class A extends B { static prototype(){} }',
    'class A extends B { static set prototype(a) {} }',
    'new.target',
    '(class {[super.a](){}});',
    '(class {[super()](){}});',
    //'!{ __proto__: null, __proto__: null, };',
    //'!{ __proto__: null, "__proto__": null };',
    "function a([]){'use strict';}",
    'for(const a = 1;;) c: function b(){}',
    '!{ a() { function* b(a = super.c()){} } };',
    '({a(b){}} = 0)',
    '({a}) = 0;',
    'class A { constructor(){} constructor(){} }',
    'class A { constructor(){} "constructor"(){} }',
    '!class A { constructor(){} constructor(){} }',
    '!class A { constructor(){} "constructor"(){} }',
    'class A extends B { static get prototype(){} }',
    `class A extends B { a() { function f(){ super.b(); } } }`,
    'for(let [let] = 0;;);',
    '({ a = 0 });',
    '(...a)',
    '(a, ...b)',
    '(((...a)))',
    '(((a, ...b)))',
    '0++',
    '0--',
    '++0',
    '--0',
    '({a: 0} = 0);',
    '({get a(){}} = 0)',
    '({set a(b){}} = 0)',
    '({a(b){}} = 0)',
    '[0] = 0;',
    '0 = 0;',
    '"use strict"; +yield;',
    '"use strict"; yield:;',
    '"use strict"; +protected:0;',
    '"use strict"; +yield:0;',
    '"use strict"; +await:0;',
    '"use strict"; +async:0;',
    '"use strict"; +static:0;',
    '"use strict"; +protected;',
    '"use strict"; +public;',
    '"use strict"; +yield;',
    '"use strict"; +implements:0;',
    '"use strict"; +interface:0;',
    '"use strict"; +let:0;',
    '"use strict"; +package:0;',
    '"use strict"; +private:0;',
    '"use strict"; function a([yield]){}',
    '"use strict"; function a({yield}){}',
    '"use strict";  function a({yield=0}){}',
    '"use strict"; function a({a:yield}){}',
    '"use strict"; function a([yield,...a]){}',
    '"use strict"; class A {set a(yield){}}',
    'let a, let = 0;',
    'let a, let;',
    'for(let a, let;;);',
    'for(const let = 0;;);',
    'for(const a = 0, let = 1;;);',
    'for(let [let] = 0;;);',
    'const a;',
    "const a, b = 0;'",
    'const a = 0, b;',
    '{ const a; }',
    'function f(){ const a; }',
    'for(const a;;);',
    'for(const a = 0, b;;);',
    'for(const let in 0);',
    'for(let let of 0);',
    'for(const let of 0);',
    '{ continue; }',
    'continue',
    'if(0) continue;',
    'while(0) !function(){ continue; };',
    '{ break; }',
    'if(0) break;',
    'while(0) !function(){ break; };',
    'while(0) { function f(){ break; } }',
    'switch(0) { case 0: !function(){ break; }; }',
    'switch(0) { case 0: function f(){ break; } }',
    'switch(0) { default: function f(){ break; } }',
    'with(0) label: function f(){}',
    'function a() { "use strict"; var implements; }',
    "function a([yield,...a]){ 'use strict'; }",
    'function* a(){ function* b({c = yield}){} }',
    'while(1) b: function a(){}',
    "function a() { 'use strict'; let = 1; }",
    ` for(const a in b) d: function c(){}`,
    'class a extends b { c() { function d(c = super.e()){} } }',
    '"use strict"; (eval)=>1',
    ` /./ii`,
    `(a, ...b)`,
    ' for(const a = 1, let = 2;;);',
    ` function a() { "use strict"; private = 1; }`,
    'function a(static) { "use strict"; }',
    '({ a(){ super(); } });',
    'for(const a;;);',
    `"use strict"; for (a in let) {}`,
    'function* a(){ (b = yield* c) => 1; }',
    'for({a: 0} of 0);',
    'b: break a;',
    'let a, let = 1;',
    'class static {}',
    'while(1) !function(){ break; };',
    'function* a(){ (b = c + d(yield)) => 1; }',
    'class a {set constructor(b){}}',
    'if(1) c: b: function a(){}',
    'while(1) !function(){ continue; };',
    'function* a(b = super()){}',
    'for(let a;;) c: function b(){}',
    //  'let \\u0061, \\u{0061};',
    '({ a(){ super(); } });',
    'for(const a = 1, b;;);',
    'for([0] of 0);',
    "function a() {'use strict'; ({ b: 1, c(eval) { } }); }",
    '"use strict"; arguments => 1',
    'if(1) continue;',
    'do b: function a(){} while (1);',
    '[a] *= 0;',
    'let a, b, c, let;',
    '"use strict"; +yield',
    '"use strict"; (a = yield) => {}',
    'function *a() { ({b = yield}) => {} }',
    'function* a(){ (b = yield c) => 1; }',
    'new.target = 42',
    'var foo = 1; new.target = foo = 42',
    'for (let let in a);',
    '"use strict"; function static() { }',
    '!function* (a){ super.b }',
    'class a extends b { c() { !function* (c = super.d()){} } }',
    '"use strict"; yield:;',
    'class a extends b { static c() { super(); } }',
    'class a { set constructor(b) {} }',
    'function* a(){ ({ *b(c = yield){} }); }',
    '"use strict"; (class a { static constructor() { super() }})',
    '!{ a() { !function* (a = super.b()){} } };',
    'for(const a = 1;;) c: function b(){}',
    'function* a(){ ({b = yield}) => 1; }',
    'function* a(){ ({b = yield}) => 1; }',
    'function* a(){ (b = yield c) => 1; }',
    'class a {static [static](){};}',
    'function* a(){ function* b(c = yield){} }',
    'function a(){ c: while(1) continue b; }',
    "function a() {'use strict'; eval = 1; }",
    '("\\u{FFFFFFF}")',
    "function a() {'use strict'; function eval() { } }",
    'for(const a;;);',
    '/[a-z]/z',
    `var af = x
            => x;`,
    `"use strict"; var af = package => 1;`,
    'var af = ...x => x;',
    '"use strict"; var af = (arguments) => 1;',
    'async function a(k = super.prop) { }',
    '(async function(k = super.prop) {})',
    '(async function a(k = super.prop) {})',
    'async function a() { super.prop(); }',
    '(async function a() { super.prop(); })',
    '(async function a(k = super()) {})',
    '(async function a() { super(); })',
    '(async function a(k = await 3) {})',
    'async function a(k = await 3) {}',
    '"use strict" var af = (yield) => 1;',
    'for(const a = 1;;) c: function b(){}',
    'class a extends b { static get prototype(){} }',
    '"use strict"; var yield;',
    '"use strict"; function static() { }',
    '!function a(b){ super[1] }',
    'function* a(){ function* b({[yield]: c}){} }',
    'function a() { "use strict"; implements = 1; }',
    "function a(){ 'use strict'; function a(yield){}}",
    'for(const a in b) d: function c(){}',
    'function* g(){ (a = yield) => 0; }',
    'function* g(){ function* f(a = x + f(yield)){} }',
    'function* g(){ function* f({[yield]: a}){} }',
    'function* g(){ function* f({a = yield}){} }',
    'function* g(){ !function*(a = yield){} }',
    'function* g(){ !function*(a = yield b){} }',
    'function* g(){ !function*([a = yield]){} }',
    'function* g(){ !function*(...{a = yield}){} }',
    'function* a(){ function* b({[yield]: c}){} }',
    'function* a(){ ({ *b(c = d + e(yield)){} }); }',
    'a: while (true) { (function () { break a; }); }',
    'function a() { "use strict"; interface = 1; }',
    'function a([yield]){ "use strict"; }',
    '({set a(b){}} = 0)',
    '"use strict"; var yield;',
    'function* a(){ (b = yield c) => 1; }',
    'a: while (true) { (function () { break; }); }',
    'for(const a;;);'
  ]) {
    it(`${arg}`, () => {
      t.throws(() => {
        parseSource(`${arg}`, undefined, Context.OptionsWebCompat);
      });
    });
    it(`${arg}`, () => {
      t.throws(() => {
        parseSource(`${arg}`, undefined, Context.None);
      });
    });
    it(`${arg}`, () => {
      t.throws(() => {
        parseSource(`${arg}`, undefined, Context.Strict | Context.Module);
      });
    });
  }
});
